package gebzebelediye_server;

import java.awt.image.*;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.imageio.ImageIO;
import com.asprise.util.pdf.PDFImageWriter;
import java.util.logging.Level;
import java.util.logging.Logger;

class ClientHandler implements Runnable {

    static Lock lock = new ReentrantLock();
    Socket socket = new Socket();
    static boolean baglanti = true;
    static boolean cikis;
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    static ArrayList<Socket> sockets = new ArrayList<Socket>();
    String mevcut_ip;
    private String mesaj = "";
    BufferedReader in;
    InputStream inn;
    BufferedImage resim;
    String str = "";
    OutputStream os;
    static int boyut = 0;
    boolean dosya_alindimi = false;

    ClientHandler(Socket s) {
        socket = s;
        sockets.add(socket);

    }

    @Override
    public void run() {
        System.out.println("Yeni client baglandi: ");
        cikis = false;
        try {

            os = socket.getOutputStream();
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (baglanti) {
                lock.lock();
                ip_gir();
                lock.unlock();
                if ("p".equals(mesaj)) {
                    dosya_al();
                } else {
                    mesaj_al();
                    if (cikis) {
                        ip_gir();
                        break;
                    }
                }
            }
        } catch (IOException e) {
            System.out.println("Stream Error");
        }


    }

    private void ip_gir() {
        boolean eslesme = false;
        if (sockets.isEmpty()) {
            System.out.println("Bagli Client Bulunmamaktadir...");
        } else {
            System.out.println(" Mevcut clientlar: ");
            for (Socket soket : sockets) {
                System.out.println(soket.getLocalAddress().toString());
            }
            System.out.println("IP giriniz: ");
            try {
                mevcut_ip = input.readLine();
            } catch (IOException ex) {
                System.out.println("ip okunurken hata olustu: " + ex);
            }
            for (Socket soket : sockets) {
                if (soket.getLocalAddress().toString().equals(mevcut_ip)) {
                    eslesme = true;
                    mesaj_oku_gonder();
                }

            }

            if (!eslesme) {
                System.out.println("Yanlis giris yaptiniz!");
                ip_gir();
            }
            return;
        }
    }

    private void mesaj_oku_gonder() {

        System.out.println("Mesajinizi giriniz, tarayici icin 'p'ye basiniz: ");
        try {
            mesaj = input.readLine();
        } catch (IOException ex) {
            System.out.println("mesaj okunurken hata olustu: " + ex);
        }
        for (Socket soket : sockets) {
            PrintStream out = null;
            try {
                out = new PrintStream(soket.getOutputStream());
                out.println(mevcut_ip + "-" + mesaj);
                if (mevcut_ip.equals(soket.getLocalAddress().toString())) {
                    socket = soket;
                }
            } catch (IOException ex) {
                Logger.getLogger(ClientHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return;
    }

    private void dosya_al() {

        try {
            dosya_alindimi = true;
            int tekrar = 0;
            int artan = 0;
            try {
                boyut = Integer.parseInt(in.readLine());
            } catch (IOException ex) {
                System.out.println("Karsidan gelen veri bozuk: " + ex);
            }
            System.out.println("boyut:" + boyut);

            tekrar = boyut / Parametre.MAX_DATA_PARCA_BOYUTU;
            artan = boyut % Parametre.MAX_DATA_PARCA_BOYUTU;
            System.out.println("artan:" + artan);
            byte[] datas = new byte[boyut];

            InputStream is = null;
            try {
                is = socket.getInputStream();
            } catch (IOException ex) {
                System.out.println("socket inputstream hatasi: " + ex);
            }

            for (int i = 0; i < tekrar; i++) {
                byte[] okunan = new byte[Parametre.MAX_PARCA_BOYUTU];
                try {
                    is.read(okunan);
                } catch (IOException ex) {
                    System.out.println("byte dizisine yazma hatasi: " + ex);
                }
                int parcaSirasi = Convert32BitsToInt(okunan);
                byte[] okunanData = getDataFromPacket(okunan);
                int index = parcaSirasi * Parametre.MAX_DATA_PARCA_BOYUTU;
                for (int j = 0; j < Parametre.MAX_DATA_PARCA_BOYUTU; ++j) {                  
                    datas[index++] = okunanData[j];
                }
            }
//            if (artan != 0) {
//                try {
//                    is.read(datas, tekrar * uzunluk, artan);
//                } catch (IOException ex) {
//                    System.out.println("byte dizisine yazma hatasi: " + ex);
//                }
//            }
            if (artan != 0) {
                byte[] okunan = new byte[artan+Parametre.PARCA_HEADER_SIZE];
                try {
                    is.read(okunan);
                } catch (IOException ex) {
                    System.out.println("byte dizisine yazma hatasi: " + ex);
                }
                int parcaSirasi = Convert32BitsToInt(okunan);
                byte[] okunanData = getDataFromPacket(okunan);
                int index = parcaSirasi * Parametre.MAX_DATA_PARCA_BOYUTU;
                for (int j = 0; j < artan; ++j) {                  
                    datas[index++] = okunanData[j];
                }
            }
            inn = new ByteArrayInputStream(datas);
            resim = ImageIO.read(inn);

            PDFImageWriter writer = new PDFImageWriter(new FileOutputStream("C:\\Users\\Win7\\Desktop\\scanner\\gelen.pdf"));
            writer.open();
            writer.addImage(resim);
            writer.close();


        } catch (IOException ex) {
            System.out.println("dosya okumada hata olustu: " + ex);
        }
        System.out.println("Okuma tamamlandi");


    }

    private void mesaj_al() {

        System.out.println("Clientin bilgi girmesi  bekleniyor... ");
        try {
            if (dosya_alindimi) {
                in.skip(boyut);
            }

            str = in.readLine();
        } catch (IOException ex) {
            System.out.println("Clienttan bilgi okunurken hata olustu: " + ex);
        }
        if (!"q".equals(str)) {

            System.out.println(socket.getInetAddress().toString() + " den gelen mesaj: " + str);
        } else if ("q".equals(str)) {
            System.out.println(socket.getInetAddress().toString() + " serverdan ayrildi ");

            try {
                sockets.remove(socket);

                for (Socket a : sockets) {
                    System.out.println(a);
                }

                socket.close();
                cikis = true;

            } catch (IOException e) {
                System.out.println("Hata: " + e);
            }


        }
    }

    /**
     * verilen data dizisindeki header bilgisinden paketin kaçıncı sırada
     * olduğunu hesaplar.
     *
     * @param sayi
     * @return
     */
    private static int Convert32BitsToInt(byte[] sayi) {
        int retValue = 0;
        return retValue;
    }

    /**
     * verilen data dizisi içerisindeki header bilgisini çıkartarak saf datayı
     * return eder.
     *
     * @param datas
     * @return
     */
    private static byte[] getDataFromPacket(byte[] datas) {
        byte[] retValue= new byte[Parametre.MAX_DATA_PARCA_BOYUTU];
        for(int i=Parametre.PARCA_HEADER_SIZE;i<Parametre.MAX_PARCA_BOYUTU;i++)
            retValue[i-4]=datas[i];
        return retValue;
    }
}
